module Oos4ruby
class Site < Bean::BeanClass
  include Bean
  
  define_el_reader(
    {
      OosNamespace => [:id, :user_address, :url, :locality, :subadministrativearea, :country, :telephone],
      AppNamespace => [:edited],
      AtomNamespace => [:title, :updated, :summary, :content]
    }
  )
  
  define_attr_reader OosNamespace => {:country => :slug, :locality => :slug}
  
  alias :oos_id :id
  alias :name :title
  alias :review_title :summary
  alias :review_content :content
    
  attr_writer :review_title, :review_content, :user_address, :url, :locality, :telephone
  
  def initialize(xml, auth, slug = nil)
    @xml = xml
    @auth = auth
    if slug
      @slug = slug
      @tags_scheme = "#{TAGS_URL}/#{@slug}"
      @lists_scheme = "#{LISTS_URL}/#{@slug}"
    end
    @categories_added = []
    @categories_removed = []
  end
  
  def country=(name, slug)
    @country = REXML::Element.new('oos:country')
    @country.add_namespace('oos', OosNamespace)
    @country.add_text name 
    @country.add_attribute 'slug', slug
  end
  
  def Site.find_by_user( auth, slug, opts = {} )
    raise Oos4ruby::UnknownUser if slug.nil?
    
    uri = SITES_URL + "/#{slug}"
    uri << "?page=#{opts[:page].to_i}" if opts[:page]

    getter = HTTPInvoker.new uri, auth
    
    worked = getter.get
    
    Sites.new(Feed.read(getter.body), auth, slug) if worked
  end    
  
  def Site.dump!(opts, slug)
    require 'date'
    
    entry = create_entry    
    add_element(entry, 'author/name', slug)
    
    updated = DateTime::now.strftime("%Y-%m-%dT%H:%M:%S%z").sub(/(..)$/, ':\1')
    
    add_element entry, 'updated', updated
    add_element entry, 'id', make_id
    add_element entry, 'oos:id', opts[:id] if opts[:id]
    add_element entry, 'title', opts[:title] if opts[:title]
    add_element entry, 'oos:useraddress', opts[:user_address] if opts[:user_address]
    add_element entry, 'oos:url', opts[:url] if opts[:url]
    add_element entry, 'oos:telephone', opts[:telephone] if opts[:telephone]
    add_element entry, 'summary', opts[:review_title] if opts[:review_title]
    add_element entry, 'summary', opts[:summary] if opts[:summary] and REXML::XPath.first(entry, 'summary', XmlNamespaces).nil?
    
    if opts[:privacy]
      if opts[:privacy].is_a?REXML::Element
        entry.add_element opts[:privacy]
      elsif opts[:privacy].is_a?String         
        add_category entry, opts[:privacy], PRIVACY_URL
      end
    end
      
    if opts[:review_content] || opts[:content]
      content = opts[:review_content] || opts[:content]
      attrs = {}
      text = nil
      if content.is_a?String
        text = content
      elsif content.is_a?Hash
        text = content[:text]
        content.delete :text
        content.each_pair {|key, value| attrs[key.to_s] = value}        
      end
      add_element entry, 'content', text, attrs
    end
    
    if opts[:locality]
      name = nil
      local_slug = nil
      attrs = {}
      if opts[:locality].is_a?Hash
        name = opts[:locality][:name]
        local_slug = opts[:locality][:slug]
      elsif opts[:locality].is_a?String
        name = opts[:locality]
      end
      attrs['slug'] = local_slug if local_slug
      add_element entry, 'oos:locality', name, attrs
    end
    
    if opts[:country]
      name = opts[:country][:name]
      opts[:country].delete :name
      attrs = {}
      opts[:country].each_pair {|key, value| attrs[key.to_s] = value}
      add_element entry, 'oos:country', name, attrs
    end
    
    opts[:tags].each { |tag| add_category entry, tag, "#{TAGS_URL}/#{slug}"} if opts[:tags]
    opts[:lists].each { |list| add_category entry, list, "#{LISTS_URL}/#{slug}"} if opts[:lists]
    
    entry
  end
  
  def tags
    return @tags if @tags
    categories = @xml.match("./atom:category[@scheme=\"#{@tags_scheme}\"]")
    if categories
      @tags = categories.map { |cat|
        Category.new cat
      }
    end
    @tags
  end
  
  def lists
    return @lists if @lists
    categories = @xml.match("./atom:category[@scheme=\"#{@lists_scheme}\"]")
    if categories
      @lists = categories.map { |cat|
        Category.new cat
      }
    end
    @lists
  end
  
  def latitude
    @xml.first('./georss:where/gml:Point/gml:pos').text.
      split[0] if @xml.first('./georss:where')
  end
  
  def longitude
    @xml.first('./georss:where/gml:Point/gml:pos').text.
      split[1] if @xml.first('./georss:where')
  end
  
  def add_tag(tag)
    tag = Category.new(tag, @tags_scheme )
    @categories_added << tag
  end
  
  def add_list(list)
    list = Category.new(list, @lists_scheme )
    @categories_added << list
  end
  
  def remove_tag(tag)
    tag = Category.new(tag, @tags_scheme )
    @categories_removed << tag
  end
  
  def remove_list(list)
    list = Category.new(list, @lists_scheme )
    @categories_removed << list
  end
  
  def privacy
    return @privacy if @privacy
    @privacy = @xml.category({:scheme => PRIVACY_URL}).attributes['term']
    @privacy
  end
  
  def privacy=(privacy)    
    @privacy_updated = privacy
  end
  
  def multimedia    
    href = @xml.first('./atom:source/app:collection').attributes['href']
    
    getter = HTTPInvoker.new href, @auth
    worked = getter.get
    
    raise RuntimeError unless worked
    Medias.new(Feed.read(getter.body), @auth, @slug)
  end
  
  private
  def load!
    if @title_review
      summary = @xml.child('summary') || @xml.add_child('summary')
      summary.text = @title_review
    end

    if @content_review
      content = @xml.child('content') || @xml.add_child('content', nil, nil, {:type => 'html'})
      content.text = @content_review 
    end

    if @categories_added
      @categories_added.each { |cat|
        add_category cat.term, cat.scheme
        (@tags ||= []) << cat if cat.scheme == @tags_scheme
        (@lists ||=[]) << cat if cat.scheme == @lists_scheme
      }
      @categories_added.clear
    end
    
    if @categories_removed
      @categories_removed.each { |cat|
        remove_category cat.term, cat.scheme
        @tags = @tags.reject { |tag|
          tag.term == cat.term and tag.scheme == cat.scheme
        }
      }
      @categories_removed.clear
    end
              
    update_category @privacy_updated.term, @privacy_updated.scheme, 
      nil, @privacy_updated.scheme if @privacy_updated
    
  end
    
end
end


